package com.technodo.gamedata;

import java.util.LinkedList;
import java.util.List;

import android.util.Log;

import com.technodo.avatar.PlayerProfile;
import com.technodo.enums.ProductRespEnum;
import com.technodo.utils.GlobalPreferences;


public class PlayerBoard  {
	private String TAG = "PlayerBoard";
	/**
	 * Player
	 */
	private PlayerProfile profile;

	/**
	 * Player number (Initial number of the player)
	 */
	private Integer number;
	// FIXME: Have the icon expanded and kept here in memory

	/**
	 * Main Player of the phone
	 */
	private boolean isMe;

	/**
	 * Turn order of the player
	 */
	private Integer turnOrder;
	/**
	 * Moves Left
	 */
	private Integer movesLeft;

	/**
	 * Amount of gold owner by player
	 */
	private Integer gold;
	/**
	 * Brand Value of the player
	 */
	private Integer brandValue;
	/**
	 * List of TechCards
	 */
	private List<Tech> techCards;
	/**
	 * List of Products
	 */
	private List<Product> products;
	/**
	 * List of owner Products
	 */
	private List<Director> directors;
	/**
	 * Current Factory Level
	 */
	private Integer factory;
	/**
	 * Current Engg Level
	 */
	private Integer engg;
	/**
	 * number of green techs owned
	 */
	private int greenColorTechs;
	/**
	 * number of blue techs owned
	 */
	private int blueColorTechs;
	/**
	 * number of red techs owned
	 */
	private int redColorTechs;
	/**
	 * number of yellow techs owned
	 */
	private int yellowColorTechs;

	/**
	 * Constructor to make a new player board
	 * 
	 * @param player	Profile of the player
	 * @param me		Is the player the user of the mobile?
	 * @param numPlayer Player number
	 */
	public PlayerBoard(PlayerProfile player, boolean me, int numPlayer) {

		greenColorTechs = 0;
		blueColorTechs = 0;
		redColorTechs = 0;
		yellowColorTechs = 0;
		isMe = me;
		number = numPlayer;
		profile = player;

		// Each player get 8 gold and 0 brand value initially
		movesLeft = TechnodoConstants.TECHNODO_MOVES_PER_TURN;
		gold = TechnodoConstants.TECHNODO_START_GOLD;
		brandValue = TechnodoConstants.TECHNODO_START_BRANDVALUE;
		factory = 0;
		engg    = 0;

		// Initialise all the sets etc 
		setTechCards(new LinkedList<Tech>());
		setProducts(new LinkedList<Product>());
		setDirectors(new LinkedList<Director>());

	}	


	/**
	 * Make a particular product for this organization
	 * Algorithm:
	 * 		1. Validate that all requirements are satisfied
	 * 		2. Calculate Profit and Brand Value
	 * 		3. Distribute Profits to individual Players
	 * 		4. Add Product to Player Board
	 * 
	 * @param product		Product to be built
	 * @param tech1Owner 	Owner of Tech 1
	 * @param tech2Owner	Owner of Tech 2
	 * @param enggOwner		Engg Facility owner for this product
	 * @param factoryOwner  Factory owner for this product
	 * @param advertisement Whether the product is hot in the market
	 * @param subsidy		Whether govt is giving subsidy for this product
	 * @return success or failure
	 */
	ProductRespEnum makeProduct(Product product,
			PlayerBoard tech1Owner, PlayerBoard tech2Owner, PlayerBoard enggOwner, PlayerBoard factoryOwner, 
			boolean advertisement, boolean subsidy) {
		ProductRespEnum resp = ProductRespEnum.ITEM_UNAVAILABLE;

		return resp;

	}

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Game Play related functions and calculations

	/**
	 * Is the tech buyable?
	 * 
	 * @param tech  Technology being attempted to be bought
	 * @param board Player Board used for calculation
	 * @return
	 * 
	 * Check, if the player has enough money to buy the tech
	 * 1. For the color of the tech, check how many techs does the player have of the same color.
	 * 2. Calculate cost
	 * 3. Check if gold available > cost
	 * 
	 */
	public boolean IsTechBuyable(Tech tech) {
		// Tech is already owned and cannot be bought or transferred
		if(tech.getPlayerBoard() != null)
			return false;

		int cost = CostOfTech(tech);
		if(cost <= gold) 
			return true;
		return false;
	}
	/**
	 * Cost of tech or its value at the end of the game
	 * 
	 * @param tech  Tech to be bought
	 * @param board Player Board
	 * @return Cost of the Technology
	 */
	public int CostOfTech(Tech tech) {
		// Tech is already owned and cannot be bought or transferred
		if(tech.getPlayerBoard() != null)
			return 0;

		// Calculate number of cards of requested color
		int numColorTech = 0;
		for(Tech t : techCards) {
			if(t.getColor().getValue() == tech.getColor().getValue()) {
				numColorTech = numColorTech + 1;
			}
		}
		// Calculate cost of tech
		return CommonCalc.calculateTechCost(numColorTech);
	}

	/**
	 * Buy a particular technology and add it to player board in available tech list
	 * 
	 * @param tech Tech to be added
	 * @return
	 * 
	 *  - Subtracts gold as per cost of the technology
	 *  - Adds tech to list of owned techs by this board
	 *  - Sets board for tech
	 */
	public int BuyTech(Tech tech) {
		Log.d("test","value of temp is in buytech "+tech.getName());
		int cost = CostOfTech(tech);
		if(cost == 0) 
			throw new IllegalArgumentException ("Tech is no buildable by Player" + tech.toString() + profile.getName());
		techCards.add(tech);

		Log.i(GlobalPreferences.TAG, "Player " + profile.getName() + " added " + " Tech : " + tech.getName() + " for Gold : " + cost);
		spendGold(cost);

		// Set tech to remove from free pool
		tech.setPlayerBoard(this);

		return cost;		
	}

	/**
	 Is the director buyable?
	 * 
	 * @param director  Director being attempted to be bought
	 * @param board Player Board used for calculation
	 * @return
	 * 
	 * Check, if the player has enough money to buy the director
	 * 1. check how many director does the player have.
	 * 2. Calculate cost
	 * 3. Check if gold available > cost
	 */
	public boolean isDirectorBuyable() {
		boolean flag = false;
		// calculate cost of director
		int cost = costOfDirector();
		if(cost <= gold) 
			flag = true;
		return flag;
	}

	/**
	 * Cost of director or its value at the end of the game
	 * 
	 * @return Cost of the Director
	 */
	public int costOfDirector() {
		int cost = 0;

		int numDirector = directors.size();
		cost = CommonCalc.calculateDirectorCost(numDirector);
	
		return cost;
	}

	/**
	 * Buy a particular director and add it to player board in available director list
	 * 
	 * @param director Director to be added
	 * @return
	 * 
	 * - Subtracts gold as per cost of the director
	 * - Adds director to list of owned directors by this board
	 * - Sets board for director
	 */
	public int BuyDirector(Director director) {
		int cost = costOfDirector();
		if(cost == 0)
			throw new IllegalArgumentException("Director is not buyable by Player" + director.toString() + profile.getName());
		directors.add(director);

		Log.i(TAG, "Player " + profile.getName() + " added " + " Director : " + director.getName() + " for Gold : " + cost);
		spendGold(cost);

		// Set director to remove from free pool
		director.setPlayerBoard(this);
		return cost;
	}

	/**
	 * Is the engg buyable?
	 * 
	 * @return
	 * 
	 * Check if the player has enough money to buy the engg
	 */
	public boolean IsEnggBuyable() {
		boolean flag = false;
		int cost = CommonCalc.calculateTechCost(this.engg);

		if(cost <= this.getGold())
			flag = true;
		return flag;		
	}

	/**
	 * Takes engineering to the next level
	 * 
	 * @return cost of buying engg
	 */
	public int BuyEngg() {
		if(engg == 4) 
			throw new IllegalStateException("Cannot buy more than max engg level on Player Board" + this.toString()); 
		int cost = 	CommonCalc.calculateTechCost(this.engg);		

		// increment engg level by 1
		this.setEngg(getEngg() + 1);

		// decrease the gold count
		this.spendGold(cost);

		return cost;
	}

	/**
	 * Is the factory buyable?
	 * 
	 * @return
	 * 
	 * Check if the player has enough money to buy the factory
	 */
	public boolean IsFactoryBuyable() {
		boolean flag = false;
		int cost = CommonCalc.calculateTechCost(this.factory);

		if(cost <= this.getGold())
			flag = true;
		return flag;		
	}	

	/**
	 * Takes factory to the next level
	 * 
	 * @return cost of buying factory
	 */
	public int BuyFactory() {
		if(factory == 4)
			throw new IllegalStateException("Cannot buy more than max factory level on Player Board" + this.toString());
		int cost = CommonCalc.calculateTechCost(this.factory);

		// increment factory level by 1
		this.setFactory(getFactory() + 1);
		
		// decrease the gold count
		this.spendGold(cost);

		return cost;
	}

	/**
	 * @return the profile
	 */
	public PlayerProfile getPlayerProfile() {
		return profile;
	}

	/**
	 * @param profile the profile to set
	 */
	public void setProfile(PlayerProfile profile) {
		this.profile = profile;
	}
	/**
	 * @return the number
	 */
	public Integer getNumber() {
		return number;
	}
	/**
	 * @param number the number to set
	 */
	public void setNumber(Integer number) {
		this.number = number;
	}
	/**
	 * @return the isMe
	 */
	public boolean isMe() {
		return isMe;
	}
	/**
	 * @param isMe the isMe to set
	 */
	public void setMe(boolean isMe) {
		this.isMe = isMe;
	}
	/**
	 * @return the turnOrder
	 */
	public Integer getTurnOrder() {
		return turnOrder;
	}
	/**
	 * @param turnOrder the turnOrder to set
	 */
	public void setTurnOrder(Integer turnOrder) {
		this.turnOrder = turnOrder;
	}
	/**
	 * @return the movesLeft
	 */
	public Integer getMovesLeft() {
		return movesLeft;
	}
	/**
	 * @param movesLeft the movesLeft to set
	 */
	public void setMovesLeft(Integer movesLeft) {
		this.movesLeft = movesLeft;
	}
	public void useMoves() {
		this.movesLeft = this.movesLeft - 1;
		if(movesLeft < 0) throw new IllegalStateException("Player Board Moves left less than 0 : " + this.toString());
	}
	/**
	 * @return the gold
	 */
	public Integer getGold() {
		return gold;
	}
	/**
	 * Spend gold equal to cost
	 */
	public void spendGold(int cost) {
		this.gold = this.gold - cost;
		if(this.gold < 0) 
			throw new IllegalStateException("Gold has gone below 0 for Player : " + profile.getName() + "Player Board : " + profile.toString());
	}
	/**
	 * Earn gold equal to profit
	 */
	public void earnGold(int profit) {
		this.gold = this.gold + profit;
		if(this.gold < 0) 
			throw new IllegalStateException("Gold has gone below 0 for Player : " + profile.getName() + "Player Board : " + profile.toString());
	}
	/**
	 * @return the brandValue
	 */
	public Integer getBrandValue() {
		return brandValue;
	}
	/**
	 * @param brandValue the brandValue to set
	 */
	public void setBrandValue(Integer brandValue) {
		this.brandValue = brandValue;
	}

	public List<Tech> getTechCards() {
		return techCards;
	}

	public void setTechCards(List<Tech> techCards) {
		this.techCards = techCards;
	}

	public List<Product> getProducts() {
		return products;
	}

	public void setProducts(List<Product> products) {
		this.products = products;
	}

	public List<Director> getDirectors() {
		return directors;
	}

	public void setDirectors(List<Director> directors) {
		this.directors = directors;
	}

	public Integer getFactory() {
		return factory;
	}

	public void setFactory(Integer factory) {
		this.factory = factory;
	}

	public Integer getEngg() {
		return engg;
	}

	public void setEngg(Integer engg) {
		this.engg = engg;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "PlayerBoard [profile=" + profile.toString() + ", number=" + number
				+ ", isMe=" + isMe + ", turnOrder=" + turnOrder
				+ ", movesLeft=" + movesLeft + ", gold=" + gold
				+ ", brandValue=" + brandValue + ", techCards=" + techCards
				+ ", products=" + products + ", directors=" + directors
				+ ", factory=" + factory + ", engg=" + engg + "]";
	}


	public Integer getGreenColorTechs() {
		return greenColorTechs;
	}


	public void updateGreenColorTechs() {
		this.greenColorTechs = greenColorTechs+1;
	}


	public Integer getBlueColorTechs() {
		return blueColorTechs;
	}


	public void updateBlueColorTechs() {
		this.blueColorTechs = blueColorTechs+1;
	}


	public Integer getRedColorTechs() {
		return redColorTechs;
	}


	public void updateRedColorTechs() {
		this.redColorTechs = redColorTechs+1;
	}

	public Integer getYellowColorTechs() {
		return yellowColorTechs;
	}

	public void updateYellowColorTechs() {
		this.yellowColorTechs = yellowColorTechs+1;
	}
	
	public int getBV(int noCards){
		switch(noCards){
		case 0 : return 0;
		case 1 : return 1;
		case 2 : return 4;
		case 3 : return 8;
		case 4 : return 16;
		default :return -1;
		}
	}
	
}
